#pragma once
#include "matrix.h"

// -- forward declaration
struct Matrix4x4;

// =================================================================================================
// Vector class in homogenous coordinates
// =================================================================================================
struct Vector4 {
	float x;
	float y;
	float z;            
        float w;

        Vector4 operator+(const Vector4& vec);
        Vector4 operator+=(Vector4& vec);
        Vector4 operator*(const Matrix4x4& mat);
        Vector4 operator*=(Matrix4x4& mat);
        Vector4 operator*(const float num);
        Vector4 operator*=(float num);
};

// =================================================================================================
// Operator overloads
// =================================================================================================
inline Vector4 Vector4::operator+(const Vector4& vec) {
    Vector4 temp;

    temp.x = x + vec.x;
    temp.y = y + vec.y;
    temp.z = z + vec.z;
    temp.w = w + vec.w;

    return temp;
}

inline Vector4 Vector4::operator+=(Vector4& vec) {
    Vector4 temp;

    temp.x = x + vec.x;
    temp.y = y + vec.y;
    temp.z = z + vec.z;
    temp.w = w + vec.w;

	*this = temp;

    return temp;
}

inline Vector4 Vector4::operator*(const Matrix4x4& mat) {
    Vector4 temp;

    temp.x = x*mat.m00 + y*mat.m10 + z*mat.m20 + w*mat.m30; 
    temp.y = x*mat.m01 + y*mat.m11 + z*mat.m21 + w*mat.m31; 
    temp.z = x*mat.m02 + y*mat.m12 + z*mat.m22 + w*mat.m32; 
    temp.w = x*mat.m03 + y*mat.m13 + z*mat.m23 + w*mat.m33; 

    return temp;
}

inline Vector4 Vector4::operator*=(Matrix4x4& mat) {
    Vector4 temp;

    temp.x = x*mat.m00 + y*mat.m10 + z*mat.m20 + w*mat.m30; 
    temp.y = x*mat.m01 + y*mat.m11 + z*mat.m21 + w*mat.m31; 
    temp.z = x*mat.m02 + y*mat.m12 + z*mat.m22 + w*mat.m32; 
    temp.w = x*mat.m03 + y*mat.m13 + z*mat.m23 + w*mat.m33; 

	*this = temp;

    return temp;
}

inline Vector4 Vector4::operator*(float num) {
    Vector4 temp;

    temp.x = x * num;
    temp.y = y * num;
    temp.z = z * num;
    
    return temp;
}

inline Vector4 Vector4::operator*=(float num) {
    Vector4 temp;

    temp.x = x * num;
    temp.y = y * num;
    temp.z = z * num;

	*this = temp;
    
    return temp;
}



// =================================================================================================
// Scalar and vector multiplication these are for symmetry
// =================================================================================================
inline Vector4 operator*(float num,const Vector4& vec) {
    Vector4 temp;

    temp.x = vec.x * num;
    temp.y = vec.y * num;
    temp.z = vec.z * num;

    return temp;
}

// =================================================================================================
// Scalar and vector multiplication these are for symmetry
// =================================================================================================
inline Vector4 operator*=(float num, Vector4& vec) {
    Vector4 temp;

    temp.x = vec.x * num;
    temp.y = vec.y * num;
    temp.z = vec.z * num;

	vec = temp;

    return temp;
}
